package cn.kgc.websocket;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONUtil;
import cn.kgc.base.SystemConstant;
import cn.kgc.entity.ChatMsg;
import cn.kgc.entity.DataContent;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.handler.codec.http.websocketx.TextWebSocketFrame;

import java.util.Date;
import java.util.List;

public class ChatHandler extends SimpleChannelInboundHandler<TextWebSocketFrame> {


    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, TextWebSocketFrame textWebSocketFrame) throws Exception {

        // 服务端中如何获得  客户端App 小程序 与服务端连接的channel
        // 前端程序 App 小程序 在启动的时候需要向服务端发送一条建立连接的消息  服务端就可以获得到客户端与服务端通道

        //获得前端发送给服务端的消息（JSON格式的字符串）
        DataContent dataContent = JSONUtil.toBean(textWebSocketFrame.text(), DataContent.class);

        //从DataContent获得消息
        ChatMsg chatMsg = dataContent.getChatMsg();

        //获得消息发送者的Id
        String senderId = chatMsg.getSenderId();

        //获得消息接收者的id
        String receiverId = chatMsg.getReceiverId();

        //如果消息的类型是0  表示客户端给服务端发送的建立连接的消息

        //获得发送类型的类型
        Integer msgType = chatMsg.getMsgType();
        //获得发送消息的通道
        Channel channel = channelHandlerContext.channel();
        if (msgType.equals(SystemConstant.CHAT_MSG_TYPE_CONNECT)) {
            //如果消息的类型是建立连接  将消息的Id  用户 Id  通道保存到会话中
            UserChannelSession.putMultiChannels(senderId, channel);
            //将用户ID和通道ID保存到会话中
            UserChannelSession.putUserChannelIdRelation(senderId, channel.id().asLongText());
        } else {
            //无论发什么消息  对于聊天服务来说都是接收到消息发送的ChatMsg
            //服务器端只要ChatMsg对象发送给消息的接收方即可

            if (msgType.equals(SystemConstant.CHAT_MSG_TYPE_AUDIO)) {
                //如果发送的是语音消息  语音消息默认是未读的
                chatMsg.setIsRead(SystemConstant.CHAT_AUDIO_IS_NOT_READ);
            }


            //无论消息接收者是否在线  设置下消息的发送时间
            chatMsg.setChatTime(new Date());

            dataContent.setChatTime(DateUtil.now());

            //根据接收者的ID获得消息的接受者的通道
            List<Channel> multiChannels = UserChannelSession.getMultiChannels(receiverId);
            if (CollUtil.isEmpty(multiChannels)) {
                //如果接收者的通道为空 则表示接收者不在线 标识一下接受者不在线  再将消息保存到数据库中
                chatMsg.setReceiverOnline(false);
            } else {
                // 如果接收者在线 给接收者的所有channel  发送消息
                chatMsg.setReceiverOnline(true);
                for (Channel tempChannel : multiChannels) {
                    //通过channel 将dataContext的json 格式的字符串发送给App端
                    tempChannel.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(dataContent)));
                }
            }
            //如果发送者  是多端登录  手机  电脑
            // 是否要同步到其他端
            List<Channel> sendChannel = UserChannelSession.getMultiChannels(senderId);
            sendChannel.removeIf(temp -> temp.id().asLongText().equals(channel.id().asLongText()));

            if (CollUtil.isNotEmpty(sendChannel)) {
                for (Channel channel1 : sendChannel)
                    channel1.writeAndFlush(new TextWebSocketFrame(JSONUtil.toJsonStr(dataContent)));
            }

            //无论接收者是否在线  都将消息保存到数据库中
        }


    }


    /**
     * 如果用户手动关闭通道 从用户的Id对应的所有通道中删除用户关闭的通道
     */
    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {
        //获得通道ID
        String channelId = ctx.channel().id().asLongText();
        //从会话中移除通道ID对应的用户ID
        UserChannelSession.removeUselessChannel(channelId);
    }
}
